package com.budwk.app.sqfw.services.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.alibaba.fastjson.JSONObject;
import com.budwk.app.common.config.AppException;
import com.budwk.app.sqfw.component.BuildingInfoComonent;
import com.budwk.app.sqfw.constants.CommonConstants;
import com.budwk.app.sqfw.dto.building.BuildQueryReqVo;
import com.budwk.app.sqfw.dto.building.BuildingInfoDTO;
import com.budwk.app.sqfw.enums.SupportBusinessTypeEnum;
import com.budwk.app.sqfw.models.BuildingInfo;
import com.budwk.app.sqfw.models.HouseInfo;
import com.budwk.app.sqfw.services.BuildingInfoService;
import com.budwk.app.sqfw.services.HouseInfoService;
import com.budwk.app.sqfwV2.component.HouseholdComponent;
import com.budwk.app.sqfwV2.dto.vo.BuildingUnitVo;
import com.budwk.app.sys.models.Sys_user;
import com.budwk.app.sys.services.SysUserService;
import com.budwk.app.util.DateUtils;
import com.budwk.starter.common.page.Pagination;
import com.budwk.starter.common.result.Result;
import com.budwk.starter.database.service.BaseServiceImpl;
import com.budwk.starter.security.utils.SecurityUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

@IocBean(args = {"refer:dao"})
@Slf4j
public class BuildingInfoServiceImpl extends BaseServiceImpl<BuildingInfo> implements BuildingInfoService {
    public BuildingInfoServiceImpl(Dao dao) {
        super(dao);
    }

    @Inject
    private SysUserService userService;
    @Inject
    private HouseInfoService houseInfoService;

    @Inject("taskQueryExecutor")
    private ThreadPoolExecutor taskQueryExecutor;


    private void insertData(BuildingInfo buildingInfo) {
        // 3 组装详细地址（五级+小区名称+楼栋地址）
        Sys_user user = userService.fetch(SecurityUtil.getUserId());
        String detailAddress = String.format("%s%s%s%s%s%s%s", user.getProvince(), user.getCity(), user.getDistrict(),
                user.getCounty(), user.getCommunity(), buildingInfo.getResidentialArea(), buildingInfo.getBuildingName());
        buildingInfo.setDetailAddress(detailAddress);
        // 4 入库
        buildingInfo.setCreateBy(SecurityUtil.getUserId()).setCreateTime(LocalDateTime.now())
                .setDeleted(false)
                .setProvince(user.getProvince())
                .setCity(user.getCity())
                .setDistrict(user.getDistrict())
                .setCounty(user.getCounty())
                .setCommunity(user.getCommunity())
                .setUpdateId(SecurityUtil.getUserId()).setUpdateTime(LocalDateTime.now());
        BuildingInfo info = findByDetailAddress(detailAddress);
        if (info != null) {
            throw new AppException("楼栋已存在，请勿重复添加！");
        }
        if (CollectionUtil.isNotEmpty(buildingInfo.getBuildUnits())) {
            if (StringUtils.isEmpty(buildingInfo.getIsFill()) || CommonConstants.NO_CHINA.equals(buildingInfo.getIsFill())) {
                buildingInfo.setIsFill(CommonConstants.YES_CHINA).setFillDate(LocalDateTime.now());
            }
        }
        if (buildingInfo.getCompletionTime() != null) {
            String comYear = LocalDateTimeUtil.format(buildingInfo.getCompletionTime(), DatePattern.NORM_YEAR_PATTERN);
            buildingInfo.setCompletionYear(Integer.parseInt(comYear));
        }
        this.insert(buildingInfo);
    }

    private BuildingInfoDTO updateData(BuildingInfoDTO dto) {
        BuildingInfo buildingInfo = dto.getBuildingInfo();
        if (StringUtils.isEmpty(buildingInfo.getId())) {
            throw new AppException("参数id不能为空！");
        }
        BuildingInfo building = this.fetch(buildingInfo.getId());
        // 1 校验修改数
        BuildingInfoComonent.checkUpdateParam(dto, building);
        // 3 组装详细地址（五级+小区名称+楼栋地址）
        Sys_user user = userService.fetch(SecurityUtil.getUserId());
        String detailAddress = String.format("%s%s%s%s%s%s%s", user.getProvince(), user.getCity(), user.getDistrict(),
                user.getCounty(), user.getCommunity(), buildingInfo.getResidentialArea(), buildingInfo.getBuildingName());
        buildingInfo.setDetailAddress(detailAddress).setUpdateId(SecurityUtil.getUserId()).setUpdateTime(LocalDateTime.now());
        BuildingInfo buildingInfo1 = findByDetailAddress(detailAddress);
        if (buildingInfo1 != null) {
            if (!buildingInfo1.getId().equals(buildingInfo.getId())) {
                throw new AppException("楼栋信息已存在");
            }
        }
        // 4 入库
        if (CollectionUtil.isNotEmpty(buildingInfo.getBuildUnits())) {
            if (StringUtils.isEmpty(building.getIsFill()) || CommonConstants.NO_CHINA.equals(building.getIsFill())) {
                buildingInfo.setIsFill(CommonConstants.YES_CHINA).setFillDate(LocalDateTime.now()).setFillNum(0);
            }
        }
        this.updateIgnoreNull(buildingInfo);
        String userId = SecurityUtil.getUserId();
        // 没有建立房屋信息 ，初始化房屋信息异步执行
        houseInfoService.initSaveHouse(buildingInfo, userId, building);
        // 记录修改记录
        if (CollectionUtil.isNotEmpty(buildingInfo.getBuildUnits())) {
            HouseholdComponent.insertRecord(JSONObject.toJSONString(buildingInfo), SupportBusinessTypeEnum.BUILD_TYPE.getName(), detailAddress);
        }
        return dto;
    }

    @Override
    @Aop(TransAop.READ_COMMITTED)
    public BuildingInfoDTO submitData(BuildingInfoDTO dto) {
        // 1 校验提交参数
        BuildingInfoComonent.checkSubmitParam(dto);
        BuildingInfo buildingInfo = dto.getBuildingInfo();
        if (StringUtils.isEmpty(buildingInfo.getId())) {
            insertData(buildingInfo);
            return dto;
        }
        // 修改
        updateData(dto);
        return dto;
    }

    @Override
    public BuildingInfo findByDetailAddress(String detailAddress) {
        Cnd cnd = Cnd.NEW();
        SqlExpressionGroup where = cnd.where();
        where.andEquals(BuildingInfo::getDetailAddress, detailAddress).andEquals(BuildingInfo::isDeleted, false);
        return this.fetch(cnd);
    }

    @Override
    public Result<?> listByPage(BuildQueryReqVo reqVo) {
        Cnd cnd = Cnd.NEW();
        // 1 组装查询条件
        SqlExpressionGroup where = BuildingInfoComonent.buildCommonSqlExpress(cnd, reqVo);
        // 检查用户数据查询权限
        HouseholdComponent.handleUserQueryAuth(where);
        String lastDay = DateUtils.getCurrentDataLastDayStr(reqVo.getFillDate() + "-01");
        if (StringUtils.isNotEmpty(reqVo.getFillDate())) {
            if ("desc".equals(reqVo.getSort())) {
                where.andBetween(BuildingInfo::getFillDate, "1970-01-01 00:00:00", lastDay);
            } else {
                where.andBetween(BuildingInfo::getFillDate, lastDay, new Date());
            }
        }
        // 2 数据查询
        cnd.getOrderBy().desc(BuildingInfo::getUpdateTime);
        Pagination pagination = this.listPage(reqVo.getPageNo(), reqVo.getPageSize(), cnd);
        int totalCount = pagination.getTotalCount();
        if (totalCount > 0) {
            // 导入的数据一般没有详细地址 需要初始化更新
            List<BuildingInfo> list = pagination.getList(BuildingInfo.class);
            CompletableFuture.runAsync(() -> HouseholdComponent.initUpdateBuildInfo(list), taskQueryExecutor);
        }
        return Result.data(pagination);
    }


    @Override
    public void deleteBuilding(BuildingInfo info) {
        // 1 校验提交参数
        BuildingInfoComonent.checkDeleteParam(info);
        //
        BuildingInfo buildingInfo = this.fetch(info.getId());
        if (buildingInfo == null) {
            throw new AppException("数据不存在！");
        }
        // 如果楼栋下有房屋存在 更新删除
        buildingInfo.setDeleteReason(info.getDeleteReason()).setDeleted(true);
        this.updateIgnoreNull(buildingInfo);
        log.info("deleteBuilding end");
    }

    /**
     * 该接口主要实现导入的数据对房屋和楼栋之间建立关系
     */
    @Override
    @Aop(TransAop.READ_COMMITTED)
    public void buildHouseRelate() {
        log.info("开始清洗数据.....................");
        Cnd cnd = Cnd.NEW();
        SqlExpressionGroup where = cnd.where();
        where.andIsNull(BuildingInfo::getIsFill)
                .andNotIsNull(BuildingInfo::getBuildingName);
        List<BuildingInfo> list = this.query(cnd);
        if (list.size() == 0) {
            throw new AppException("无数据需要清洗！");
        }
        log.info("开始查询房屋数据...........");
        Cnd cnd1 = Cnd.NEW();
        SqlExpressionGroup where1 = cnd1.where();
        where1.andIsNull(HouseInfo::getIsFill)
                .andNotIsNull(HouseInfo::getDoorNumber);
        List<HouseInfo> listHouse = houseInfoService.query(cnd1);


        log.info("未清洗的房屋数据量为：...........: {} 条数据", listHouse.size());
        // 1 清洗楼栋到房屋
//        try {
//            for (BuildingInfo buildingInfo : list) {
//                updateRelation(buildingInfo, listHouse);
//            }
//        } catch (Exception e) {
//            log.error("errOr: ", e);
//        }

        // 2 清洗房屋到楼栋
        try {
            qxB(listHouse, list);
        } catch (Exception e) {
            log.error(" qxB(listHouse);: ", e);
        }
        log.info("----------------------------------数据清洗完成-------------------------------------");
    }

    private void qxB(List<HouseInfo> listHouse, List<BuildingInfo> buildingInfos) {
        if (listHouse.size() > 0) {

            Map<String, String> map = new HashMap<>();
            for (HouseInfo houseInfo : listHouse) {
                String doorNumber = houseInfo.getDoorNumber();
                String soureStr = doorNumber.substring(0, doorNumber.lastIndexOf("栋") + 1);
                map.put(soureStr.replace("/", ""), soureStr);
            }
            for (Map.Entry<String, String> entry : map.entrySet()) {
                String doorNumber = entry.getKey();
                List<BuildingInfo> list = buildingInfos.stream().filter(e -> e.getBuildingName().contains(doorNumber)).collect(Collectors.toList());
                if (list.size() == 1) {
                    BuildingInfo buildingInfo = list.get(0);
                    // 获取总的户数
                    List<HouseInfo> house = listHouse.stream().filter(e -> e.getDoorNumber().contains(entry.getValue())).collect(Collectors.toList());
                    List<String> ids = new ArrayList<>();
                    updateQXData(buildingInfo, house, ids);
                    if (ids.size() > 0) {
                        listHouse.removeIf(e -> ids.contains(e.getId()));
                    }
                }
            }
        }
    }

    private void updateRelation(BuildingInfo buildingInfo, List<HouseInfo> listHouse) {
        // 获取总的户数
        List<HouseInfo> house = listHouse.stream().filter(e -> e.getDoorNumber().contains(buildingInfo.getBuildingName())).collect(Collectors.toList());
        List<String> ids = new ArrayList<>();
        updateQXData(buildingInfo, house, ids);
        if (ids.size() > 0) {
            listHouse.removeIf(e -> ids.contains(e.getId()));
        }
    }

    private void updateQXData(BuildingInfo buildingInfo, List<HouseInfo> house, List<String> ids) {
        Integer householdsCount = buildingInfo.getHouseholdsCount();

        if (house.size() == householdsCount) {
            house.forEach(e -> e.setBuildingId(buildingInfo.getId()).setIsFill(CommonConstants.NO_CHINA).setHouseNumber(e.getRoomNumber()));
            // 取出所有的单元信息
            List<String> units = house.stream().map(HouseInfo::getUnit).distinct().collect(Collectors.toList());
            List<BuildingUnitVo> buildUnits = new ArrayList<>();
            for (String unit : units) {
                BuildingUnitVo unitVo = new BuildingUnitVo();
                int minFloor = house.stream().filter(e -> e.getUnit().equals(unit)).mapToInt(HouseInfo -> Integer.parseInt(HouseInfo.getFloor())).min().getAsInt();
                int maxFloor = house.stream().filter(e -> e.getUnit().equals(unit)).mapToInt(HouseInfo -> Integer.parseInt(HouseInfo.getFloor())).max().getAsInt();
                unitVo.setUnitName(unit).setFloorsCount(maxFloor).setFloorHouses(householdsCount/maxFloor).setStartFloor(minFloor).setHasElevator("是").setStepNumber(maxFloor);
                buildUnits.add(unitVo);
            }

            houseInfoService.updateIgnoreNull(house);
            buildingInfo.setIsFill(CommonConstants.YES_CHINA)
                    .setFillDate(LocalDateTime.now())
                    .setBuildUnits(buildUnits)
                    .setFillNum(0)
                    .setUnitNumber(units.size());
            this.updateIgnoreNull(buildingInfo);
            if (ids != null) {
                ids.addAll(house.stream().map(HouseInfo::getId).collect(Collectors.toList()));
            }
        }
    }

}
